try {
	Tests.blah
} catch (e) {
	Tests = {};
}

Tests.ArrayTests = new Class({
	setup: function () {
		this.array = ['a', 'b', 'c'];
	},

	testFindFoundByIndex: function () {
		for (i = 0; i < this.array.length; i++) {
			assertEquals(i, 
				this.array.find(function (item, index) {
					return i === index;
				}));
		}
		assertTrue(this.array.find(function () { return false;}) < 0);
	},
	
	testFindFoundByValue: function () {
		var fn = function (item, index) {
			return this.array[i] === item;
		}.bind(this);
		
		for (i = 0; i < this.array.length; i++) {
			assertEquals(i, this.array.find(fn));
		}
	},
	
	testBinarySearchFoundByValue: function () {
		var compareString = function(a, b) {
			return a > b ? 1 : a <  b ? -1 : 0;
		};
		
		for (i = 0; i < this.array.length; i++) {
			assertEquals(i, this.array.binarySearch(compareString, this.array[i]));
		}
		assertTrue(this.array.binarySearch(compareString, 'bogus') < 0);
	},
	
	testUnqiue: function () {
		var a = 'a';
		var origLength = this.array.length;
		assertTrue(this.array.contains(a));
		this.array.push(a);
		assertEquals(origLength + 1, this.array.length);
		assertEquals(a, this.array.getLast());
		this.array = this.array.unique();
		assertEquals(origLength, this.array.length);
		assertNotEquals(a, this.array.getLast());
	},
	
	testUniqueWithClosure: function () {
		var a = 'A';
		var origLength = this.array.length;
		assertTrue(this.array.contains(a.toLowerCase()));
		this.array.push(a);
		assertEquals(origLength + 1, this.array.length);
		assertEquals(a, this.array.getLast());
		this.array = this.array.unique(function (str1, str2) {
			return str1.toLowerCase() == str2.toLowerCase();
		});
		assertEquals(origLength, this.array.length);
		assertNotEquals(a, this.array.getLast());
	},
	
	testSame: function () {
		assertTrue(this.array.same(this.array));
		assertFalse(this.array.same([]));
		var differentArray = [1, 2, 3];
		assertEquals(differentArray.length, this.array.length);
		assertFalse(this.array.same(differentArray));
	}
});

/* ------------------------------------------------------------------------------------- */

Tests.NumberTests = new Class({
	
	testFixedString: function () {
		assertEquals("1", (1).fixedString(1));
		assertEquals("01", (1).fixedString(2));
		assertEquals("001", (1).fixedString(3));
		assertEquals("099", (99).fixedString(3));
		assertEquals("99", (99).fixedString(1));
		assertEquals("10", (10).fixedString(1));
		assertEquals("10", (10).fixedString(2));
		assertEquals("010", (10).fixedString(3));
	},
	
	testInRange: function () {
		const n = 5;
		assertTrue(n.inRange(n,n+1));
		assertFalse(n.inRange(n+1,n+2));
		assertTrue(n.inRange(n-1,n+1));
		assertFalse(n.inRange(n-1,n));
	}
	
});

/* ------------------------------------------------------------------------------------- */

Tests.StringTests = new Class({
	testEndsWith: function () {
		var string = "a random string";
		for (i = 0; i < string.length; i++) {
			assertTrue(string.endsWith(string.substring(i)));
		}
		
		string = string.toUpperCase();
		for (i = 0; i < string.length; i++) {
			assertTrue(string.endsWith(string.substring(i).toLowerCase(), true));
		}
		
		assertFalse(string.endsWith("bogus string"));
	},
	
	testFormat: function () {
		assertEquals("1, 2", "?, ?".format(1, 2));
		assertEquals("1, ", "?, ?".format(1));
		assertEquals("hello, world", "?, ?".format('hello', 'world'));
	},
	
	testStartsWith: function () {
		var string = "a random string";
		for (i = 1; i < string.length; i++) {
			assertTrue(string.startsWith(string.substring(0, i)));
		}
		
		string = string.toUpperCase();
		for (i = 1; i < string.length; i++) {
			assertTrue(string.startsWith(string.substring(0, i).toLowerCase(), true));
		}
		
		assertFalse(string.startsWith("bogus string"));
	}
});

/* ------------------------------------------------------------------------------------- */

Tests.ElementTests = new Class({
	setup: function () {
		this.el = new Element('text', {
			hOffset: 1,
			vOffset: 2,
			width: 3,
			height: 4
		});
	},
	
	testGetBounds: function () {
		var expectedBounds = Rectangle.create(this.el.hOffset, this.el.vOffset, this.el.width, this.el.height);
		var actualBounds = this.el.getBounds();
		assertEquals(expectedBounds.x, actualBounds.x);
		assertEquals(expectedBounds.y, actualBounds.y);
		assertEquals(expectedBounds.width, actualBounds.width);
		assertEquals(expectedBounds.height, actualBounds.height);
	},
	
	testToggleStyle: function () {
		var defaultStyle = {
			color: '#FFFFFF',
			backgroundColor: '#000000'
		};
		var newStyle = {
			color: '#000000',
			backgroundColor: '#FFFFFF'
		};
		
		this.el.setStyles(defaultStyle);
		this.el.toggleStyle('test', defaultStyle, newStyle);
		assertEquals(newStyle.color, this.el.style.color);
		assertEquals(newStyle.backgroundColor, this.el.style.backgroundColor);
		this.el.toggleStyle('test', defaultStyle, newStyle);
		assertEquals(defaultStyle.color, this.el.style.color);
		assertEquals(defaultStyle.backgroundColor, this.el.style.backgroundColor);
	}
});

/* ------------------------------------------------------------------------------------- */
Tests.ClassTests = new Class({
	setup: function () {
		this.aClass = new Class({
			instanceVar: 10,
			
			aMethod: function () {
				
			},
			
			get getter () {
				return true;
			},
			
			set setter (val) {
				this.instanceVar = val;
			}
		});
		this.anInstance = new this.aClass();
	},
	
	testIsInstance: function () {
		assertTrue(this.aClass.isInstance(this.anInstance));
		assertFalse(this.aClass.isInstance(1));
		assertFalse(this.aClass.isInstance(null));
	},
	
	testIsAssignableFrom: function () {
		assertFalse(this.aClass.isAssignableFrom(null));
		assertFalse(this.aClass.isAssignableFrom(String));
		assertTrue(this.aClass.isAssignableFrom(this.aClass));
		
		var childClass = this.aClass.extend({
			newMethod: function () {},
			aMethod: function () { this.parent(); }
		});
		assertTrue(this.aClass.isAssignableFrom(childClass));
	},
	
	testGetterDefined: function () {
		assertTrue(this.aClass.getterDefined('getter'));
		assertFalse(this.aClass.getterDefined('setter'));
	},
	
	testSetterDefined: function () {
		assertTrue(this.aClass.setterDefined('setter'));
		assertFalse(this.aClass.setterDefined('getter'));
	},
	
	testDefineGetter: function () {
		var newGetter = function () {
			return false;
		}
		this.aClass.defineGetter('getter', newGetter);
		assertTrue(this.anInstance.getter);
		this.aClass.defineGetter('getter', newGetter, true);
		assertFalse(this.anInstance.getter);
		
		assertFalse(this.aClass.getterDefined('anotherGetter'));
		this.aClass.defineGetter('anotherGetter', newGetter);
		assertFalse(this.anInstance.anotherGetter);
	},
	
	testDefineSetter: function () {
		var newSetter = function (val) {
			this.instanceVar = val + 1;
		}
		
		const value = 10;
		this.aClass.defineSetter('setter', newSetter);
		this.anInstance.setter = value;
		assertEquals(value, this.anInstance.instanceVar);
		
		this.aClass.defineSetter('setter', newSetter, true);
		this.anInstance.setter = value;
		assertEquals(value + 1, this.anInstance.instanceVar);
		
		assertFalse(this.aClass.setterDefined('anotherSetter'));
		this.aClass.defineSetter('anotherSetter', newSetter);
		this.anInstance.anotherSetter = value;
		assertEquals(value + 1, this.anInstance.instanceVar);
	}
});

Tests.FetchResultTests = new Class({
	setup: function () {
		this.db = new SQLite();
		this.dbPath = system.widgetDataFolder + '/test.db';
		this.deleteDb();
		this.db.open(this.dbPath);
		
		this.db.exec('CREATE TABLE IF NOT EXISTS `test` (' +
				'`id` INTEGER PRIMARY KEY, ' +
				'`item` INTEGER NOT NULL' +
				');');
		this.db.exec('INSERT INTO `test` VALUES(1, 1)');
		this.db.exec('INSERT INTO `test` VALUES(2, 1)');
		this.db.exec('INSERT INTO `test` VALUES(3, 2)');
	},
	
	deleteDb: function () {
		if (filesystem.itemExists(this.dbPath)) {
			filesystem.moveToRecycleBin(this.dbPath);
		}
	},
	
	teardown: function () {
		this.db.close();
		this.deleteDb();
	},
	
	testFetchResult: function () {
		assertEquals(3, fetchResult(this.db.query('SELECT count(*) FROM test;')));
		assertEquals(2, fetchResult(
			this.db.query('SELECT id FROM test WHERE item=1 ORDER BY id;'), 1));
		assertEquals(1, fetchResult(
			this.db.query('SELECT id, item FROM test WHERE item=1 ORDER BY id;'), 1, 'item'));
		assertEquals(2, fetchResult(
			this.db.query('SELECT id, item FROM test WHERE item=1 ORDER BY id;'), 1, 0));
		
		assertFalse(fetchResult(
			this.db.query('SELECT id, item FROM test WHERE item=1 ORDER BY id;'), 2, 0));
	}
});

/**
 * @TODO toString are not tested yet... 
 */
Tests.TimeTests = new Class({
	testValueOf: function () {
		for (var i = 0; i < 100; i++) {
			var time = new Time({second: i});
			assertEquals(i, time.valueOf());
		}
	},
	
	testEquals: function () {
		var time = new Time({second: 10});
		assertFalse('different type', time.equals(10));
		assertTrue('same seconds value', time.equals(new Time({second: 10})));
		assertFalse('different time', time.equals(new Time({second: 15})));
	}
});